package com.changjiang.tool.util;

import com.changjiang.tool.exception.VelocityException;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;

import java.io.File;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URL;
import java.util.*;

/**
 * @author : Chen Changjiang
 * @date : 2020/05/03
 * @description :
 */
public class VelocityUtil {
    private VelocityEngine ve = new VelocityEngine();
    private static final Map<String, Template> VELOCITY_TEMPLATE_MAP = new HashMap<>(32);
    private static volatile VelocityUtil velocityUtil;

    private static final String DEFAULT_CHARSET = "UTF-8";
    private static final Set<String> TEMPLATE_FILE_NAME_SET = new HashSet<>(32);

    /**
     * @param templateNameAndFileName 键将作为模板名称，值必须为classpath下的模板文件名称
     * @return
     */
    public static VelocityUtil getInstance(Map<String, String> templateNameAndFileName) {
        paramCheck(templateNameAndFileName);

        if (velocityUtil != null) {
            return velocityUtil;
        }
        synchronized (VelocityUtil.class) {
            if (velocityUtil == null) {
                velocityUtil = new VelocityUtil(templateNameAndFileName);
            }
            return velocityUtil;
        }
    }

    private VelocityUtil(Map<String, String> templateNameAndFileName) {
        initialVelocityEngine();
        initialVelocityTemplate(templateNameAndFileName);
    }

    private void initialVelocityEngine() {
        ve.setProperty(Velocity.RESOURCE_LOADER, "class");
        ve.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        ve.init();
    }

    /**
     * @param templateNameAndFileName 键将作为模板名称，值必须为classpath下的模板文件名称
     */
    private void initialVelocityTemplate(Map<String, String> templateNameAndFileName) {
        for (Map.Entry entry : templateNameAndFileName.entrySet()) {
            String templateName = entry.getKey().toString();
            String fileName = entry.getValue().toString();
            Template template = ve.getTemplate(fileName, DEFAULT_CHARSET);
            VELOCITY_TEMPLATE_MAP.put(templateName, template);
        }
    }

    /**
     * 获取一个装载模板名称的Set
     *
     * @return
     */
    public Set<String> getTemplateNamesSet() {
        return TEMPLATE_FILE_NAME_SET;
    }

    /**
     * 根据模板创建文件
     *
     * @param templateName 模板名称
     * @param fileName     创建的文件的绝对路径
     * @param paramMaps    模板中需要装填的参数
     * @throws IOException
     */
    public void buildVelocityFile(String templateName, String fileName, Map<String, Object> paramMaps) throws IOException {
        //检查参数
        if (!TEMPLATE_FILE_NAME_SET.contains(templateName)) {
            throw new VelocityException("模板名称错误");
        }
        //构造文件
        Template template = VELOCITY_TEMPLATE_MAP.get(templateName);

        VelocityContext velocityContext = new VelocityContext();
        for (Map.Entry entry : paramMaps.entrySet()) {
            velocityContext.put(entry.getKey().toString(), entry.getValue());
        }

        FileWriter fileWriter = new FileWriter(new File(fileName));
        template.merge(velocityContext, fileWriter);
        fileWriter.close();
    }

    private static void paramCheck(Map<String, String> templateNameAndFileName) {
        if (templateNameAndFileName == null || templateNameAndFileName.isEmpty()) {
            throw new VelocityException("模板名与文件不能为空");
        }
        URL resource = VelocityUtil.class.getResource("/");
        File directory = new File(resource.getFile());
        String[] resourceFileList = directory.list(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                if (name.contains(".vm")) {
                    return true;
                }
                return false;
            }
        });
        if (resourceFileList == null || resourceFileList.length == 0) {
            throw new VelocityException("指向文件为空");
        }
        System.out.println(Arrays.toString(resourceFileList));

        List<String> fileNameList = Arrays.asList(resourceFileList);
        for (Map.Entry entry : templateNameAndFileName.entrySet()) {
            String fileName = entry.getValue().toString();
            if (!fileNameList.contains(fileName)) {
                throw new VelocityException("模板中文件名与类路径下的模板文件名不匹配");
            }
            TEMPLATE_FILE_NAME_SET.add(fileName);
        }
    }
}
